﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using WatiN.Core;
using WatiN.Core.Native;
using WatiN.Core.Logging;
using WatiN.Core.UtilityClasses;
using WatiN.Core.Properties;
using WatiN.Core.Native.Windows;
using WatiN.Core.DialogHandlers;
using WatiN.Core.Exceptions;

using WatiNSahi.Extensions;
using System.Diagnostics;

namespace WatiNSahi
{
    public abstract partial class WatiNSahiTest
    {

        #region ACTIONS

        /// <summary>
        /// To navigate to given url.
        /// </summary>
        /// <param name="url"></param>
        public static void _navigateTo(string url)
        {
            _log("Hello WatiN Sahi .NET!");

            if(baseURL != null)
            {
                /// TODO: Put a check whether base URL end with forward slash and also url starts with forward slash
                url = baseURL + url;
            }
            _initialize();
            
            hwnd = browser.hWnd;
            PID = browser.ProcessID;
            browser.GoTo("about:blank");
            browser.GoTo(url);
            try
            {
                _wait_for_complete(140);
            }
            catch (Exception)
            {

                Console.WriteLine("Process busy exiting the session..");
                _close();
            }

     

        }


        public static void _closeBrowser()
        {
            //br.Close();
            _close();

        }

        public static void _openBrowser()
        {
            browser.Reopen();
        }

        public static List<Frame> _get_browser_frames()
        {
            List<Frame> allFrames = new List<Frame>();
            foreach (var frame in browser.Frames)
            {
#if DEBUG
                _log(string.Format("Details of Parent Frame => Name :: '{0}' ID :: '{1}' ", frame.Name, frame.Id));
#endif       
                allFrames.Add(frame);
                allFrames.AddRange(_get_frames(frame));
            }
            return allFrames;
        }

        public static List<Frame> _get_frames(Frame parentFrame)
        {
            List<Frame> frameList = new List<Frame>();

            foreach (var child in parentFrame.Frames)
            {
#if DEBUG
                _log(string.Format("Details of Child Frame => Name :: '{0}' ID :: '{1}' ", child.Name, child.Id));
#endif
                frameList.Add(child);
                if(parentFrame.Frames.Count>0)
                    frameList.AddRange(_get_frames(child));
            }

            return frameList;           

        }

        public static Element _find_element_in_given_frame(string nameOrId, Frame frame)
        {
            Element elm = null;

            try
            {
                elm = frame.Element(Find.ByName(nameOrId).Or(Find.ById(nameOrId)));
            }
            catch(ElementNotFoundException we)
            {
                _logException("Element was not found. Message :: " + we.Message);
            }

            return elm;
        }

        public static void _print_browser_frames_details()
        {
            foreach (var frame in browser.Frames)
            {
                _log(string.Format("Details of Frame => Name :: '{0}' ID :: '{1}' ", frame.Name, frame.Id));
                _print_frames_details(frame);
            }

        }
        public static void _print_frames_details(Frame parentFrame)
        {
            foreach (var frame in parentFrame.Frames)
            {
                _log(string.Format("Details of Frame => Name :: '{0}' ID :: '{1}' ", frame.Name, frame.Id));
                if (parentFrame.Frames.Count > 0)
                    _print_frames_details(frame);
            }

        }

        /// <summary>
        /// Click on the given element
        /// </summary>
        /// <param name="elm"></param>
        public static void _click(Element elm)
        {
            
            print_element_info(elm, "Click");

            try
            {
                elm.Click();
            }
            catch (Exception we)
            {
                Console.WriteLine("WatiN Exception occured :: " + we.Message);
            }

            _wait_for_complete();
        }


        /// <summary>
        /// Click on the given element and dont wait for action to complete.
        /// </summary>
        /// <param name="elm"></param>
        public static void _click_no_wait(Element elm)
        {

            print_element_info(elm, "Click No Wait");
            try
            {
                elm.ClickNoWait();
            }
            catch (WatiNException we)
            {
                Console.WriteLine("Element not found.");
                Console.WriteLine("WatiN Exception occured :: " + we.Message);
            }

            _wait_for_complete();

        }

        /// <summary>
        /// Fire Mouse Over Event on the given Element
        /// </summary>
        /// <param name="elm"></param>
        public static void _mouseOver(Element elm)
        {
            print_element_info(elm, "Mouse Over");
            try
            {
                elm.FireEvent("mouseover");
                
            }
            catch (Exception we)
            {

                _logException(string.Format("Exception occurred with Message :: '{0}'",we.Message));
                elm.FireEvent("onmouseover");
            }

        }

        /// <summary>
        /// Set a given value for the given element.
        /// </summary>
        /// <param name="elm"></param>
        /// <param name="val"></param>
        public static void _setValue(Element elm, string val)
        {
            
            print_element_info(elm, "Set Value");
            try
            {
                elm.SetAttributeValue("value", val);                
            }
            catch (Exception e)
            {
                _wait(500);
                var textBox = elm as TextField;
                try
                {
                    _logException(string.Format("Exception occured with Message :: '{0}'", e.Message));
                    textBox.TypeText(val);
                }
                catch (Exception ex)
                {
                    _logException(string.Format("Exception occured with Message :: '{0}'",ex.Message));
                }

            }

        }


        /// <summary>
        /// Close the browser.
        /// </summary>
        public static void _close()
        {
            _log("Attempting to close the browser window.");
            Process procBrowser = null;

            
            browser.Close();
            //if ("firefox".Equals(browserName))
            //{
            //    br.Dispose();
            //}
            _wait(2000);

            try 
            {
               procBrowser  = Process.GetProcessById(PID);
            }
                catch(ArgumentException )
            {
                _log("Browser was successfully closed.");
            }
            catch(Exception e)
            {
                _logException(string.Format("Exception occurred with Message :: '{0}' and exception type was :: '{1}'",
                    e.Message,e.GetType().ToString()));

            }
            
            if(procBrowser!=null)
            {
                if (procBrowser.HasExited)
                {
                    browser = null;
                }
                else
                {
                    _log("Browser was not closed properly. Killing the browser process using its PID.");
                    procBrowser.Kill();
                    browser = null;
                }
            }
            
            
            

            if (browser == null)
            {
                _log("Browser was successfully closed.");
            }
            //else
            //{
            //    try
            //    {
            //        Process myBrowser = Process.GetProcessById(PID);
            //        myBrowser.Kill();
            //    }
            //    catch(Exception)
            //    {
            //        Console.WriteLine(string.Format("No Process with '{0}' exists.",PID));
            //    }
            //    finally
            //    {
            //        Console.WriteLine("Browser was killed successfully.");
            //    }
            //}
        }

        #endregion

        #region PRINT GET FUNCTIONS - ATTRIBUTES ETC.

        private static void print_element_info(Element elm, string action)
        {
            string name = null;
            string id = null;
            string value = null;
            string text = null;
            string title = null;
            string outerText = null;

            if (_check_null(elm)) // If element is null will return true
            {
                _logException("Element is null or does not exists.");
                return;
            }
                
            

            try
            {
                name = elm.Name;
                id = elm.Id;
                value = elm.GetAttributeValue("value");
                text = elm.Text;
                title = elm.Title;
                outerText = elm.OuterText;
            }
            catch (Exception)
            {
            }

            Console.WriteLine(string.Format("Performing action '{0}' on element of type '{7}' with " +
                "name : '{1}', id : '{2}'," +
                "value : '{3}', text : '{4}', title : '{5}', outerText : '{6}'",
                action, name, id, value, text, title, outerText, elm.GetType()));


        }

        private static bool _check_null(Element elm)
        {
            bool result = false;
            if (elm == null || !elm.Exists)
                result = true;

            return result;
        }

        /// <summary>
        /// Get ENOVIA specific table row column attributes for an element.
        /// </summary>
        /// <param name="elm"></param>
        /// <returns>An array containing rmbrow, rownumber, position and id respectively.</returns>
        public static string[] _e_get_table_attributes(Element elm)
        {
            string rmbrow = string.Empty;
            string rownumber = string.Empty;
            string position = string.Empty;
            string id = string.Empty;

            if (_check_null(elm)) // If element is null will return true
            {
                _logException("Element is null or does not exists.");                
            }
                

            try
            {
                elm.GetAttributeValue("rmbrow");
                elm.GetAttributeValue("rownumber");
                elm.GetAttributeValue("position");
                elm.GetAttributeValue("id");
            }
            catch (Exception) { }

            return new string[] { rmbrow, rownumber, position, id };
        }


        /// <summary>
        /// Print values for given array of attributes.
        /// </summary>
        /// <param name="elm"></param>
        /// <param name="vals"></param>
        /// <example>
        /// Create an array of attributes and pass it to the function.
        /// <code>
        /// var attrs = new string[] { "name", "value", "text", "id", "class" };
        /// _print_attributes_values(_textbox("login_password"), attrs);
        /// </code>
        /// </example>
        public static void _print_attributes_values(Element elm, string[] vals)
        {
            if (elm == null)
            {
                Console.WriteLine("Element is null. Nothing will be printed.");
                return;
            }

            foreach (var val in vals)
            {
                try
                {
                    Console.WriteLine(string.Format("Value for attribute : '{0}' is : '{1}'.", val, elm.GetAttributeValue(val)));
                }
                catch (Exception)
                {
                    Console.WriteLine("Attribute not present :: " + val.ToString());
                }
            }
        }

        #endregion

        
        public static void _mouseDown()
        {

        }
        public static void _mouseUp()
        {

        }
        public static void _keyPress()
        {

        }
        public static void _focus()
        {

        }
        public static void _keyDown()
        {

        }
        public static void _keyUp()
        {

        }

        public static void _rteWrite()
        {

        }
        
        public static void _type(Element elm, string val)
        {
            TextField tf;

            tf = elm as TextField;
            tf.TypeText(val);
        }

        public static void _check()
        {

        }
        public static void _uncheck()
        {

        }
        public static void _blur(Element elm)
        {
            try
            {
                elm.Blur();
                
            }
            catch(Exception e)
            {
                _logException("Exception occured with Message :: " + e.Message);
                browser.Eval(string.Format("$('{0}').blur();", elm.GetJavascriptElementReference()));                
            }

        }
        public static void _removeFocus()
        {

        }
        public static string _getText(Element elm)
        {

            return elm.Text;
        }
        public static string _getCellText(Element elm)
        {

            return elm.OuterText;
        }
    }
}
